package main

import (
	"context"
	"fmt"
	"log"
	"math"
	"math/big"
	"os"
	"strconv"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/joho/godotenv"
	hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
	bip39 "github.com/tyler-smith/go-bip39"
)

func main() {
	fmt.Println("ETH私钥穷举器")

	// 读取RPC节点服务地址
	err := godotenv.Load()
	if err != nil {
		log.Fatalf("读取.env文件失败: %v", err)
	}
	rpcUrl := os.Getenv("RPC_URL")
	fmt.Println("RPC节点服务地址: ", rpcUrl)

	// 连接RPC节点
	client, err := ethclient.Dial(rpcUrl)
	if err != nil {
		log.Fatalf("链接RPC节点服务失败: %v", err)
	}
	defer client.Close()

// 	var input int
// 	fmt.Print("请输入您要穷举的次数: ")
// 	fmt.Scanln(&input)

    // 每天1000万次
	for i := 0; i < 10000000; i++ {
		addr, privateKey, _ := createWallet()
		balance := getBalance(client, addr)
		if balance.Cmp(big.NewFloat(0)) > 0 {
			fmt.Println(addr, privateKey)
			fmt.Printf("余额: %.4f ETH\n", balance)
			fmt.Println()

			data := []byte(addr + "，" + privateKey + "，" + balance.String())
			str := time.Now().Format("20060102150405")
			os.WriteFile("success_" + str + ".txt", data, 0644)
		} else {
		    data := []byte(strconv.Itoa(i + 1))
			os.WriteFile("count.txt", data, 0644)
		}
	}
}

// 生成钱包
func createWallet() (address, privateKey, mnemonic string) {
	// 创建128位随机熵字节
	entropy, err := bip39.NewEntropy(128)
	if err != nil {
		log.Fatalf("创建随机熵字节失败")
	}
	// 生成助记词
	mnemonic, _ = bip39.NewMnemonic(entropy)
	// 通过助记词生成钱包地址、私钥
	address, privateKey = mnemonicUnlock(mnemonic)
	return
}

// 助记词解锁
func mnemonicUnlock(mnemonic string) (address, privateKey string) {
	if ok := bip39.IsMnemonicValid(mnemonic); !ok {
		log.Fatalf("助记词无效")
	}
	seed := bip39.NewSeed(mnemonic, "")
	wallet, err := hdwallet.NewFromSeed(seed)
	if err != nil {
		log.Fatalf("从BIP-39种子生成钱包失败")
	}
	// 设置标准派生路径
	path := hdwallet.MustParseDerivationPath("m/44'/60'/0'/0/0")
	account, err := wallet.Derive(path, false)
	if err != nil {
		log.Fatalf("派生新钱包失败")
	}
	// 生成钱包地址和私钥
	address = account.Address.Hex()
	privateKey, _ = wallet.PrivateKeyHex(account)
	return
}

// 查询余额
func getBalance(client *ethclient.Client, addr string) *big.Float {
	address := common.HexToAddress(addr)

	balance, err := client.BalanceAt(context.Background(), address, nil)
	if err != nil {
		log.Fatalf("查询余额失败", err)
	}

	ethBalance := new(big.Float).SetInt(balance)
	ethBalance = ethBalance.Quo(ethBalance, big.NewFloat(math.Pow10(18)))

	return ethBalance
}
